﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

using JavaSubstitutes;

namespace Sprites
{
	//this class is basically a map of the level- where blocks are, what their attributes are, etc
	public class Level
	{

		public static string[] BIT_DESCRIPTIONS = 
		{
			"BLOCK UPPER", 
            "BLOCK ALL", 
            "BLOCK LOWER", 
            "SPECIAL", 
            "BUMPABLE", 
            "BREAKABLE", 
            "PICKUPABLE", 
            "ANIMATED",
	    };

		//this is the contents of the tiles.dat file which was being loaded
		//at runtime, but doesn't need to be (256 byte)
		//each tile has attributes that are assigned when the level is created- see the BIT_* constants below to decypher what these do
		public static byte[] TILE_BEHAVIORS = new byte[] 
		{
			0x00, 0x14, 0x1c, 0x00, 0x82, 0x82, 0x82, 0x82, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x8a, 0x00, 0xa2, 0x92, 0x9a, 0xa2, 0x92, 0x92, 0x9a, 0x92, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 
			0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
			0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 
			0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
		};

		public const int BIT_BLOCK_UPPER = 1 << 0;
		public const int BIT_BLOCK_ALL = 1 << 1;
		public const int BIT_BLOCK_LOWER = 1 << 2;
		public const int BIT_SPECIAL = 1 << 3;
		public const int BIT_BUMPABLE = 1 << 4;
		public const int BIT_BREAKABLE = 1 << 5;
		public const int BIT_PICKUPABLE = 1 << 6;
		public const int BIT_ANIMATED = 1 << 7;

		//private static int FILE_HEADER = 0x271c4178;
		public int width;
		public int height;

		public byte[,] map; //the blocks/tiles in the level
		public byte[,] data; //attributes of the block/tile. See the BIT_* consts above

		public SpriteTemplate[,] spriteTemplates;

		public int xExit;
		public int yExit;

		public Level(int width, int height)
		{
			this.width = width;
			this.height = height;

			xExit = 10;
			yExit = 10;
			map = new byte[width, height];
			data = new byte[width, height];
			spriteTemplates = new SpriteTemplate[width, height];
		}


		public static void loadBehaviors(DataInputStream dis)
		{
			dis.readFully(Level.TILE_BEHAVIORS);
		}


		//public static void saveBehaviors(DataOutputStream dos)
		//{
		//    dos.write(Level.TILE_BEHAVIORS);
		//}

		//public static Level load(DataInputStream dis)
		//{
		//    long header = dis.readLong();
		//    if (header != Level.FILE_HEADER) throw new Exception("Bad level header");
		//    int version = dis.read() & 0xff;

		//    int width = dis.readShort() & 0xffff;
		//    int height = dis.readShort() & 0xffff;
		//    Level level = new Level(width, height);
		//    level.map = new byte[width, height];
		//    level.data = new byte[width, height];
		//    for (int i = 0; i < width; i++)
		//    {
		//        dis.readFully(level.map, i);
		//        dis.readFully(level.data, i);
		//    }
		//    return level;
		//}

		//public void save(DataOutputStream dos)
		//{
		//    dos.writeLong(Level.FILE_HEADER);
		//    dos.write((byte)0);

		//    dos.writeShort((short)width);
		//    dos.writeShort((short)height);

		//    for (int i = 0; i < width; i++)
		//    {
		//        dos.write(map, i);
		//        dos.write(data, i);
		//    }
		//}

		public void tick()
		{
			for (int x = 0; x < width; x++)
			{
				for (int y = 0; y < height; y++)
				{
					if (data[x, y] > 0) data[x, y]--;
				}
			}
		}

		public byte getBlockCapped(int x, int y)
		{
			if (x < 0) x = 0;
			if (y < 0) y = 0;
			if (x >= width) x = width - 1;
			if (y >= height) y = height - 1;
			return map[x, y];
		}

		public byte getBlock(int x, int y)
		{
			if (x < 0) x = 0;
			if (y < 0) return 0;
			if (x >= width) x = width - 1;
			if (y >= height) y = height - 1;
			return map[x, y];
		}

		public void setBlock(int x, int y, byte b)
		{
			if (x < 0) return;
			if (y < 0) return;
			if (x >= width) return;
			if (y >= height) return;
			map[x, y] = b;
		}

		public void setBlockData(int x, int y, byte b)
		{
			if (x < 0) return;
			if (y < 0) return;
			if (x >= width) return;
			if (y >= height) return;
			data[x, y] = b;
		}

		public bool isBlocking(int x, int y, double xa, double ya)
		{
			byte block = getBlock(x, y);
			bool blocking = ((TILE_BEHAVIORS[block & 0xff]) & BIT_BLOCK_ALL) > 0;
			blocking |= (ya > 0) && ((TILE_BEHAVIORS[block & 0xff]) & BIT_BLOCK_UPPER) > 0;
			blocking |= (ya < 0) && ((TILE_BEHAVIORS[block & 0xff]) & BIT_BLOCK_LOWER) > 0;

			return blocking;
		}

		public SpriteTemplate getSpriteTemplate(int x, int y)
		{
			if (x < 0) return null;
			if (y < 0) return null;
			if (x >= width) return null;
			if (y >= height) return null;
			return spriteTemplates[x, y];
		}

		public void setSpriteTemplate(int x, int y, SpriteTemplate spriteTemplate)
		{
			if (x < 0) return;
			if (y < 0) return;
			if (x >= width) return;
			if (y >= height) return;
			spriteTemplates[x, y] = spriteTemplate;
		}
	}
}